//
//  FInputBar.m
//  FFoundation
//
//  Created by 新庭 on 2020/2/5.
//

#import "FInputBar.h"
#import "FView.h"
#import "FInputBarTextField.h"
#import "FMacroDefine.h"

static const CGFloat FInputBarPanelDefaultProtraitHeight = 346;
static const CGFloat FInputBarPanelDefaultLandscapeHeight = 209;
@interface FInputBarItem ()

/// 缓存item对应的视图
@property (nonatomic, weak) UIView *view;

@end

@interface FInputBar ()

/// No head container -- FInputBar's height is defined by outside, if head container's height changed, can't define InputBar's height inner precise.
@property (nonatomic, strong) UIView *contentContainer;

@property (nonatomic, strong) FInputBarTextField *inputBarTextField;
@property (nonatomic, strong, readonly) UITextField *textField;
@property (nonatomic, strong) UIView *innerLeftContainer;

@property (nonatomic, strong) UIView *panelContainer;

#pragma mark -
@property (nonatomic, assign) BOOL ignoreKeyboardFrameChangeNotification;   ///< 忽略键盘位置变化行为，当面板切换时使用

@end

@implementation FInputBar

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        FInputBarPanelDefaultHeight =
        UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) ?
        FInputBarPanelDefaultLandscapeHeight : FInputBarPanelDefaultProtraitHeight;
        
        [self prepareSubviews];
    }
    return self;
}

- (void)prepareSubviews {
    [self addSubview:self.contentContainer];
    [self.contentContainer mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.mas_offset(0);
    }];
    
    /// Field Container's position can't be calculated until refresh
    [self.contentContainer addSubview:self.inputBarTextField];
    
    [self.inputBarTextField addSubview:self.textField];
    [self.textField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.mas_offset(0);
    }];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarWillRotate:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
}

- (BOOL)resignFirstResponder {
    return [self.textField resignFirstResponder];
}

- (BOOL)becomeFirstResponder {
    return [self.textField becomeFirstResponder];
}

- (BOOL)canBecomeFocused {
    return [self.textField canBecomeFocused];
}

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    BOOL inside = [self.layer.presentationLayer containsPoint:point];
    if (!inside && self.head) {
        CGPoint headLocation = [self.head convertPoint:point fromView:self];
        inside |= [self.head.layer.presentationLayer containsPoint:headLocation];
    }
    return inside;
}

- (void)setDelegate:(id<FInputBarDelegate>)delegate {
    _delegate = delegate;
    
    self.textField.delegate = delegate;
}

- (void)setPadding:(UIEdgeInsets)padding {
    _padding = padding;
    
    [self.contentContainer mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.edges.mas_offset(padding);
    }];
}

- (void)unfoldPanel:(UIView * _Nullable)panel height:(CGFloat)height {
    if (!panel) {
        // 打开默认键盘
        self.ignoreKeyboardFrameChangeNotification = YES;
        [self foldPanel];
        [self.textField becomeFirstResponder];
        [self.panelContainer cleanSubviews];
        _panel = nil;
        
        F_macro_delegate(void, self.delegate, @selector(inputBar:unfoldPanel:), self, panel);
        self.ignoreKeyboardFrameChangeNotification = NO;
        return;
    }
    
    if ([self.panelContainer.subviews.firstObject isEqual:panel]) {
        return;
    }
    
    // 收起之前的面板
    self.ignoreKeyboardFrameChangeNotification = self.textField.isFirstResponder;
    [self foldPanel];
    
    _panel = panel;
    
    self.panelContainer.jk_height = height;
    [self.panelContainer addSubview:panel];
    [panel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.mas_offset(0);
    }];
    self.textField.inputView = self.panelContainer;
    self.textField.autocorrectionType = UITextAutocorrectionTypeNo;
    [self.textField becomeFirstResponder];
    
    F_macro_delegate(void, self.delegate, @selector(inputBar:unfoldPanel:), self, panel);
    self.ignoreKeyboardFrameChangeNotification = NO;
}

- (void)foldPanel {
    UIView *panel = self.panel;
    
    self.textField.inputView = nil;
    self.textField.autocorrectionType = UITextAutocorrectionTypeDefault;
    
    [self.panelContainer cleanSubviews];
    self.panelContainer.jk_height = 0;
    [self resignFirstResponder];
    
    F_macro_delegate(void, self.delegate, @selector(inputBar:foldPanel:), self, panel);
    _panel = nil;
}

- (BOOL)isUnfolded {
    return ([self.textField isFirstResponder] || [self hasCustomPanel]);
}

- (void)unfoldHead:(UIView *)head height:(CGFloat)height {
    if (!head || [head isEqual:self.head]) {
        return;
    }
    
    [self foldHead];
    _head = head;
    
    [self.superview addSubview:head];
    head.transform = self.transform;
    [head mas_makeConstraints:^(MASConstraintMaker *make) {
        make.leading.trailing.mas_offset(0);
        make.bottom.mas_equalTo(self.mas_top);
        make.height.mas_equalTo(height);
    }];
    
    F_macro_delegate(void, self.delegate, @selector(inputBar:unfoldHead:), self, head);
}

- (void)foldHead {
    if (self.head) {
        UIView *head = self.head;
        [self.head removeFromSuperview];
        
        F_macro_delegate(void, self.delegate, @selector(inputBar:foldHead:), self, head);
        _head = nil;
    }
}

- (UIView *)viewForItem:(FInputBarItem *)item {
    return item.view;
}

- (FInputBarItem *)itemForView:(UIView *)view {
    NSInteger index = [self.items indexOfObjectPassingTest:^BOOL(FInputBarItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        return [obj.view isEqual:view];
    }];
    return index == NSNotFound ? nil : self.items[index];
}

- (void)refresh {
    if (!self.delegate) return;
    
    // remove all views in item
    for (FInputBarItem *item in self.items) {
        [item.view removeFromSuperview];
    }
    
    UIView *left = nil;
    for (FInputBarItem *item in self.items) {
        if (item.position == FInputBarItemPositionLeft) {
            UIView *view = [self renderItem:item leftView:left container:self.contentContainer];
            if (!view) continue;
            
            left = view;
        }
    }
    
    [self.inputBarTextField mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.top.bottom.mas_offset(0);
        left ?
        make.leading.mas_equalTo(left.mas_trailing) :
        make.leading.mas_equalTo(0);
    }];
    left = self.inputBarTextField;
    
    // fill inner left view
    [self fillInnerLeft:self.innerLeftContainer];
    
    for (FInputBarItem *item in self.items) {
        if (item.position == FInputBarItemPositionRight) {
            UIView *view = [self renderItem:item leftView:left container:self.contentContainer];
            if (!view) continue;
            
            left = view;
        }
    }
    [left mas_updateConstraints:^(MASConstraintMaker *make) {
        make.trailing.mas_offset(0);
    }];
}

- (void)safeAreaInsistBarHeight:(CGFloat)height {
    [self.contentContainer mas_remakeConstraints:^(MASConstraintMaker *make) {
        if (@available(iOS 11.0, *)) {
            make.top.mas_equalTo(self.mas_safeAreaLayoutGuideTop).mas_offset(self.padding.top);
            make.bottom.mas_equalTo(self.mas_safeAreaLayoutGuideBottom).mas_offset(self.padding.bottom);
            make.left.mas_equalTo(self.mas_safeAreaLayoutGuideLeft).mas_offset(self.padding.left);
            make.right.mas_equalTo(self.mas_safeAreaLayoutGuideRight).mas_offset(self.padding.right);
        } else {
            make.edges.mas_offset(self.padding);
        }
    }];
}

#pragma mark - Action
- (void)keyboardWillShow:(NSNotification *)noti {
    CGRect endFrame = [[noti.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    
    // endFrame is refer from the window coordinates, the super view may didn't as the same, so convert it.
    CGRect endFrameInSuper = [self.superview convertRect:endFrame fromView:nil];
    CGFloat delta = CGRectGetMinY(endFrameInSuper) - CGRectGetMaxY(self.frame);
    
    CGAffineTransform transform = CGAffineTransformTranslate(self.transform, 0, delta);
    self.transform = transform;
    self.head.transform = transform;
}

- (void)keyboardWillHide:(NSNotification *)noti {
    if (self.ignoreKeyboardFrameChangeNotification) {
        return;
    }
    self.transform = CGAffineTransformIdentity;
    self.head.transform = CGAffineTransformIdentity;
}

- (void)statusBarWillRotate:(NSNotification *)noti {
    UIInterfaceOrientation orientation = [[noti.userInfo objectForKey:UIApplicationStatusBarOrientationUserInfoKey] integerValue];
    
    FInputBarPanelDefaultHeight = UIInterfaceOrientationIsLandscape(orientation) ? FInputBarPanelDefaultLandscapeHeight : FInputBarPanelDefaultProtraitHeight;
    
    // 重建，使高度更新
    self.panelContainer = nil;
}

#pragma mark - Private
- (UIView *)renderItem:(FInputBarItem *)item leftView:(UIView *)left container:(UIView *)container {
    __block UIView *view = nil;
    if (item.type == FInputBarItemTypeDefault) {
        view = [self.delegate inputBar:self willRenderItem:item];
    } else if (item.type == FInputBarItemTypeStack) {
        NSInteger index = [self.items indexOfObject:item];
        NSArray<FInputBarItem *> *sameNameItems = [[self.items subarrayWithRange:NSMakeRange(0, index)] jk_filter:^BOOL(FInputBarItem * object) {
            return object.type == FInputBarItemTypeStack && [object.name isEqualToString:item.name];
        }];
        
        FInputBarItem *toppestItem = [sameNameItems jk_detect:^BOOL(FInputBarItem *object) {
            return object.view;
        }];
        
        if (toppestItem) {
            // 如果相同name的stack类型item，已经有视图返回，则当前的item不渲染
        } else {
            view = [self.delegate inputBar:self willRenderItem:item];
        }
    } else {}
    
    
    if (!view) return nil;
    
    item.view = view;
    [container addSubview:view];
    
    FInputBarItem *preItem = [self itemForView:left];
    [view mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.centerY.mas_offset(0);
        
        left ?
        make.leading.mas_equalTo(left.mas_trailing).mas_offset(item.insets.left + preItem.insets.right) :
        make.leading.mas_equalTo(item.insets.left);
        
        make.width.mas_equalTo(item.size.width);
        item.size.height > 0 ?
        make.height.mas_equalTo(item.size.height) :
        make.height.mas_equalTo(self);
    }];
    F_macro_delegate(void, self.delegate, @selector(inputBar:didRenderedItem:withView:), self, item, view);
    return view;
}

- (void)fillInnerLeft:(UIView *)container {
    self.textField.leftView = nil;
    
    UIView *left = nil;
    for (FInputBarItem *item in self.items) {
        if (item.position == FInputBarItemPositionInnerLeft) {
            UIView *view = [self renderItem:item leftView:left container:container];
            if (!view) continue;
            
            left = view;
        }
    }
    [left mas_updateConstraints:^(MASConstraintMaker *make) {
        make.trailing.mas_offset(0);
    }];
    
    if (left) {
        self.textField.leftView = self.innerLeftContainer;
    }
}

- (BOOL)hasCustomPanel {
    return self.panelContainer.subviews.count > 0;
}

- (UIView *)contentContainer {
    if (!_contentContainer) {
        _contentContainer = [[UIView alloc] init];
    }
    return _contentContainer;
}

- (UIView *)inputBarTextField {
    if (!_inputBarTextField) {
        _inputBarTextField = [[FInputBarTextField alloc] init];
        _inputBarTextField.textField.leftViewMode = UITextFieldViewModeAlways;
    }
    return _inputBarTextField;
}

- (UITextField *)textField {
    return self.inputBarTextField.textField;
}

- (UIView *)innerLeftContainer {
    if (!_innerLeftContainer) {
        _innerLeftContainer = [[UIView alloc] init];
    }
    return _innerLeftContainer;
}

- (UIView *)panelContainer {
    if (!_panelContainer) {
        _panelContainer = [[UIView alloc] init];
    }
    return _panelContainer;
}

- (NSMutableArray<FInputBarItem *> *)items {
    if (!_items) {
        _items = [NSMutableArray array];
    }
    return _items;
}

@end

CGFloat FInputBarPanelDefaultHeight = FInputBarPanelDefaultProtraitHeight;
